﻿package demo.app.view
{
	/**
	 * @author blackcj.com - Christopher Black - August 17, 2009
	 * 
	 * Resources: 
	 * http://www.emanueleferonato.com/2009/05/18/understanding-how-box2d-manages-boundaries/
	 * http://www.box2d.org/manual.html
	 * http://box2dflash.sourceforge.net/
	 *
	 */
	
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Common.Math.*;
	import Box2D.Dynamics.*;
	
	import demo.app.Constants;
	
	import flash.display.Sprite;
	import flash.events.Event;
	
	public class Base2dEnvironment extends Sprite
	{
		protected var box_width:int;
		protected var box_height:int;
		protected var debug_mode:Boolean;
		protected var world:b2World;
		protected var body:b2Body;
		protected var running:Boolean = false;
		protected var margin:int = 5;
		
		public function Base2dEnvironment(boxWidth:int = 800, boxHeight:int = 500, debugMode:Boolean = false)
		{
			super();
			
			box_width = boxWidth;
			box_height = boxHeight;
			debug_mode = debugMode;
			
			var gravity:b2Vec2 = new b2Vec2(0,10);
			var worldAABB:b2AABB = new b2AABB();
			
			worldAABB.lowerBound.Set(-100,-100);
			worldAABB.upperBound.Set(100,100);
			world = new b2World(gravity, false);
			
			//Shows boundries (green transparency) used to see 'Ground'
			if(debugMode){
				drawGroundBoundries();
			}
			
			// Bottom wall
			AddStaticBox((box_width / 2)/Constants.PHYS_SCALE, (box_height + margin)/Constants.PHYS_SCALE, (box_width / 2) / Constants.PHYS_SCALE, margin / Constants.PHYS_SCALE);            
			// Top wall
			AddStaticBox((box_width / 2)/Constants.PHYS_SCALE, -margin / Constants.PHYS_SCALE, (box_width / 2) / Constants.PHYS_SCALE, margin / Constants.PHYS_SCALE);
			// Left wall
			AddStaticBox(-margin / Constants.PHYS_SCALE,(box_height / 2) / Constants.PHYS_SCALE, margin / Constants.PHYS_SCALE,(box_height / 2 ) / Constants.PHYS_SCALE);
			// Right wall
			AddStaticBox((box_width + margin) / Constants.PHYS_SCALE,(box_height / 2)/Constants.PHYS_SCALE, margin / Constants.PHYS_SCALE,((box_height) / 2) / Constants.PHYS_SCALE);
		}
		
		/*
		* PUBLIC FUNCTIONS
		*/        
		public function start():void
		{
			if(!running){
				addEventListener(Event.ENTER_FRAME, update, false, 0, true);
				running = true;
			}
		}
		
		public function pause():void
		{
			if(running){
				removeEventListener(Event.ENTER_FRAME, update);
				running = false;
			}
		}
		
		/*
		* PROTECTED FUNCTIONS
		*/        
		protected function update(e:Event):void {
			world.Step(Constants.TIMESTEP, Constants.ITERATIONS, Constants.ITERATIONS);
			world.ClearForces();
			world.DrawDebugData();
		}
		
		/*
		* PRIVATE FUNCTIONS
		*/
		private function drawGroundBoundries():void
		{
			var m_sprite:Sprite;
			m_sprite = new Sprite();
			addChild(m_sprite);
			
			var dbgDraw:b2DebugDraw = new b2DebugDraw();
			var dbgSprite:Sprite = new Sprite();
			m_sprite.addChild(dbgSprite);
			dbgDraw.SetSprite(m_sprite);
			dbgDraw.SetDrawScale(Constants.PHYS_SCALE);
			dbgDraw.SetAlpha(1);
			dbgDraw.SetFillAlpha(0.5);
			dbgDraw.SetLineThickness(1);
			dbgDraw.SetFlags(b2DebugDraw.e_shapeBit);
			world.SetDebugDraw(dbgDraw);
		}
		
		// Used for drawing the ground
		private function AddStaticBox(_x:Number,_y:Number,_halfwidth:Number,_halfheight:Number):void {
			var bodyDef:b2BodyDef = new b2BodyDef();
			bodyDef.position.Set(_x, _y);
			
			var boxDef:b2PolygonShape = new b2PolygonShape();
			boxDef.SetAsBox(_halfwidth, _halfheight);
			
			var fixtureDef:b2FixtureDef = new b2FixtureDef();
			fixtureDef.shape = boxDef;
			fixtureDef.density = 0.0;
			
			var body:b2Body = world.CreateBody(bodyDef);
			body.CreateFixture(fixtureDef);
		}        
	}
}